cocurrent 'S3Eco'

new3SEco =: 3 : 0
boardLoc  =. cocreate ''
coinsert__boardLoc 'S3Eco'

names     =. 'steps dim prop pgrow energy cost'
pnames    =. 'pmin pmax ptime'
enames    =. 'ep eh ec'
cnames    =. 'ch cc'

cocurrent boardLoc
(names)      =: y
(pnames)     =: pgrow
(enames)     =: 0j1 * energy
(cnames)     =: 0j1 * cost
iterateBoard =: iterateBoard_S3Eco_ f.
run          =: run_S3Eco_ f.
makeMove     =: makeMove_S3Eco_ f.
cocurrent 'S3Eco'

boardLoc
)

scale =: % +/

speciesRanges =: +/\ @: (] * scale@[)
getSpeci =: ([: <. 0 { +.) " 0
getEnergy=: 1 { +.
buildSpeci=: + (* 0j1&[)

makeBoard =: [ $ (+/ @: (speciesRanges <"0 _ ?~@]) */ @ ])~
initEnergy=: ]`(] + [ {~ 3 = ])@.(+./"1@:(2 3 = ])"_ 0)

shiftBy      =: 9 2 $ _1 _1   _1 0   _1 1   0 _1   0 1   1 _1   1 0   1 1   0 0
neighborArray=: shiftBy&(|. " 1 _)
neighList    =: }:@({"0 2~ <)~
withinBounds =: [ |(+ ([: > 0 { ]) + [: {&shiftBy ({~ ?@#)~ @ ([: > 1 { ]))

disp =: (' PHC')&({~"1 0) @ getSpeci
stats=: (# %~ ((+/"1@:="1 0) 0 1 2 3&[))@:getSpeci@:, 

SKIP =: _
calcNewStack =: ]`(]&SKIP) @. = " 0


run  =: 3 : 0
echo disp board =. (eh , ec) initEnergy dim makeBoard prop
steps iterateBoard board
)

iterateBoard =: 4 : 0
'steps board' =. x ; y
if. steps = 0 do. board else.
	res =. (?~ */ dim) makeMove board
	echo'END MOVE'
	echo disp newBoard =. {: res
	echo ''
	echo stats board
	echo ''
	(<: steps) iterateBoard newBoard
end.
)

makeMove =: 4 : 0 NB. Takes movestack, board
'stack board' =. x ; y
if. 0 = # stack do. ,: board else.
	if. SKIP = {. stack do. board makeMove~ }. stack else.
	coor =. dim #: ({. stack)
	'newBoard newStack' =. (neighborArray board) (blankMove ` plantMove ` herbivoreMove ` carnivoreMove @. ([: getSpeci board {::~ > @ {. @ ]) ) coor ; stack
NB.	echo newBoard
NB.	echo ''
	newBoard , (}. newStack) makeMove newBoard
	end.
end.
)

blankMove =: 4 : 0
'neighBoard coor stack' =. x ; y
board             =. {: neighBoard
NB. echo (": coor) , ' is a blank'
plantNeigh =. getSpeci +/ 1 = (< coor) ({ " 0 2) neighBoard
if. (plantNeigh >: pmin) *. plantNeigh <: pmax do.
	NB.echo disp board
	NB.echo 'board change'
	res =.((%. x: ptime) + (<coor) { board) (<coor)}board
	NB. echo disp res
	res ; stack
	else. 
		NB.echo disp board
		board ; stack
end.
)

plantMove =: 4 : 0
NB. Plants don't move, silly!
'neighBoard coor stack' =. x ; y
board                   =. {: neighBoard
NB. echo (": coor) , ' is a plant'
board ; stack
)

herbivoreMove =: 4 : 0
'neighBoard coor stack' =. x ; y
board                   =. {: neighBoard
NB. echo (": coor) , ' is a herbivore'
nextEn =. getEnergy ch -~ coor {:: board
if. 0 >: nextEn do. (0 (<coor)}board) ; stack else.
	plantLocs =. I. 1 = nl =. getSpeci coor neighList neighBoard
	if. 0 ~: # plantLocs do. NB. Plant nearby
		newCoor =. dim withinBounds coor ; plantLocs
		addEn =. nextEn + getEnergy ep
		update =. (0 , 2&buildSpeci)`((eh + 2:) , 2&buildSpeci - eh&[)@.(>: getEnergy@(eh * 2:)) addEn
		res =. update (coor ; newCoor)}board
		res ; (dim #. newCoor) calcNewStack stack
	else. NB. The harvest left no food for you to eat!
NB.		echo ' no food!'
		newCoor =. dim withinBounds coor ; 8 , blankLocs =. I. 0 = nl
		((0 , 2 buildSpeci nextEn) (coor ; newCoor)}board) ; stack
	end.
end.
)

carnivoreMove =: 4 : 0
'neighBoard coor stack' =. x ; y
board                   =. {: neighBoard
NB. echo (": coor) , ' is a carnivore'
nextEn =. getEnergy cc -~ coor {:: board
if. 0 >: nextEn do. (0 (<coor)}board) ; stack else.
	herbLocs =. I. 2 = nl =. getSpeci coor neighList neighBoard
NB.	echo nl
NB.	echo herbLocs
NB.	echo > (' food' ; ' no food') {~ 0 ~: # herbLocs
	if. 0 ~: # herbLocs do. NB. Herbivore nearby
NB.		echo ' assumed food'
		newCoor =. dim withinBounds coor ; herbLocs
		addEn   =. nextEn + getEnergy eh
		update  =. (0 , 3&buildSpeci)`((ec + 2:) , 3&buildSpeci - eh&[)@.(>: getEnergy@(ec * 2:)) addEn
		res     =. update (coor ; newCoor)}board
		res ; (dim #. newCoor) calcNewStack stack
	else.
NB.		echo ' assumed no food'
		blankLocs =. I. 0 = nl
		otherLocs =. 8 , I. 1 = nl
		newCoor =. dim withinBounds coor ; (blankLocs&[)`(otherLocs&[)@.(0 = [: # blankLocs&[) ''
		((0 , 3 buildSpeci nextEn) (coor ; newCoor)}board) ; stack
	end.
end.
)

cocurrent 'base'

loc =. new3SEco_S3Eco_ args =: 30 ; 15 15 ; 6 6 2 1; 3 8 2 ; 1 3 4 ; 0.4 0.5
run__loc ''
